package controller;

import java.util.ArrayList;

import dto.ColumnDTO;
import dto.QueryParserDTO;
import dto.RowDTO;

public class QueryController {
	private String _query;
	private QueryParser _parser;

	public QueryController(String _query) {
		super();
		this._query = _query;
		this._parser = new QueryParser(this._query);
	}

	@SuppressWarnings("unchecked")
	public EQueryType executeQuery() throws Exception {
		QueryParserDTO info = this._parser.parse();
		if (info == null) {
			return null;
		}

		EQueryType type = info.getType();
		DatabaseController dbCtrl;
		TableController tblCtrl;

		switch (type) {
		case CREATE_DATABSE:
			System.out.println(this._query);
			// create database controller with dbname
			dbCtrl = new DatabaseController(info.getData().get(0).toString());
			dbCtrl.createDatabase();
			return EQueryType.CREATE_DATABSE;
		case CREATE_TABLE:
			System.out.println(this._query);
			String tableName = info.getData().get(0).toString();

			@SuppressWarnings("unchecked")
			ArrayList<ColumnDTO> columns = (ArrayList<ColumnDTO>) info
					.getData().get(1);
			if (tableName == null || columns == null) {
				throw new Exception("Invalid table name");
			}

			if (ControllerConfiguration.DEFAULT_DATABASE.isEmpty()) {
				throw new Exception("Default database is not set yet!");
			}
			tblCtrl = new TableController(
					ControllerConfiguration.DEFAULT_DATABASE, tableName,
					columns);
			if (!tblCtrl.createTable()) {
				throw new Exception("Invalid table name");
			}
			return EQueryType.CREATE_TABLE;
		case DROP_DATABASE:
			System.out.println(this._query);
			// Drop database
			dbCtrl = new DatabaseController(info.getData().get(0).toString());
			// If drop failed.
			if (!dbCtrl.dropDatabase()) {
				throw new Exception("Database name is invalid");
			}
			return EQueryType.DROP_DATABASE;
		case DROP_TABLE:
			System.out.println(this._query);
			if (ControllerConfiguration.DEFAULT_DATABASE.isEmpty()) {
				throw new Exception("Default database is not set yet!");
			}
			// Drop database
			tblCtrl = new TableController(
					ControllerConfiguration.DEFAULT_DATABASE, info.getData()
							.get(0).toString());
			// If drop failed.
			if (!tblCtrl.dropTable()) {
				throw new Exception("Table name is invalid");
			}
			return EQueryType.DROP_TABLE;
		case INSERT:
			if (ControllerConfiguration.DEFAULT_DATABASE.isEmpty()) {
				throw new Exception("Default database is not set yet!");
			}
			// 1. Get table name
			String tblName = (String) info.getData().get(0);
			tblCtrl = new TableController(
					ControllerConfiguration.DEFAULT_DATABASE, tblName);

			ArrayList<String> cols;
			ArrayList<Object> values;
			if (info.getData().size() == 2) {
				values = (ArrayList<Object>) info.getData().get(1);
			} else {
				cols = (ArrayList<String>) info.getData().get(1);
				values = (ArrayList<Object>) info.getData().get(2);

				// Validate columns
				ArrayList<ColumnDTO> colDTOs = tblCtrl.getTableColumns();
				if (colDTOs == null) {
					throw new Exception("Table '" + tblName + "' is not exists");
				} else {
					if (cols.size() != colDTOs.size()
							|| cols.size() != values.size()) {
						throw new Exception("Number of columns is invalid");
					} else {
						for (int i = 0; i < cols.size(); i++) {
							if (cols.get(i) != colDTOs.get(i).getName()) {
								throw new Exception("Columns name is not valid");
							}
						}
					}
				}
			}

			// 2. Insert data
			ArrayList<RowDTO> rows = new ArrayList<RowDTO>();
			RowDTO row = new RowDTO(values);
			rows.add(row);
			tblCtrl.insertRows(rows);

			return EQueryType.INSERT;
		case SELECT:
			return EQueryType.SELECT;
		default:
			break;
		}
		return null;
	}
}
